/**
 * 概念：
 * 随着一个量的变化，随之变化一致的成为协变，而变化相反的成为逆变。
 * 在 ts 中描述为：
 * 协变的作用：将子类型赋值给父类型。
 * 逆变的作用：父类型可以赋值给子类型
 * 其实就是类型保护
 */

type Animal = {
  eat(): void;
};
type Pet = Animal & {
  run(): void;
};
type Dog = Pet & {
  bark(): void;
};
let a: Animal = {
  eat() {
    console.log("eat");
  },
};
let p: Pet = {
  eat() {
    console.log("eat");
  },
  run() {
    console.log("run");
  },
};
let d: Dog = {
  eat() {
    console.log("eat");
  },
  run() {
    console.log("run");
  },
  bark() {
    console.log("bark");
  },
};
// function feed(pet: Pet) {
//   pet.run();
// }
// feed(d); // dog 是 pet的子类型，子类型涵盖了父类型的方法和属性，因此可以成功
// feed(p);
// feed(a); // 报错，因为 父类型可能不包含函数中要用到的子类型中才有的属性和方法。

// function feed(cb: (p: Pet) => Pet): void {}

// function petToPet(p: Pet): Pet {
//   return p;
// }
// function petToDog(p: Pet): Dog {
//   return d;
// }
// function petToAnimal(a: Animal): Animal {
//   return a;
// }

// feed(petToPet);
// feed(petToDog);
// feed(petToAnimal); // 在参数相同的情况下，函数返回值类型支持协变 子类 -> 父类 因为返回值得类型是付类型，对函数中的调用是不安全的。

// 函数参数的逆变
// 函数参数的逆变是：返回的类型一致的情况下，参数支持逆变。因为？传递进来的函数被调用时，如果参数是父类型，函数中执行的话就有问题了。

/**
 * 1. 需要传递的类型是：(pet: 父类型): 父类型
 * 2. 传递进来的函数是：(dog: 子类型): 父类型
 */

// function clone(f: (p: Pet) => Pet): void {}

// function petToPet(p: Pet): Pet {
//   return p;
// }
// function animalToPet(a: Animal): Pet {
//   return p;
// }
// function dogToPet(d: Dog): Pet {
//   return p;
// }
// clone(petToPet);
// clone((d: Dog) => {
//   d.bark();
//   return p;
// }); // 不能将Pet分配给Dog因为Pet中缺少bark属性
// clone(animalToPet);

// const person = {
//   id: 1,
//   message: "你好",
// } as const;

// type PersonType = typeof person;

// type objLength = {
//   length: number;
// };

// function getObj<T extends objLength>(obj: T) {
//   return obj;
// }
// getObj("hello world");
// // getObj(123); // error
// getObj([1, 2, 3]);
// getObj({ a: "aa", length: 1 });

// // 得到传进来的t的message值的类型 extends 受限的泛型
// type Message<T extends { message: unknown }> = T["message"];

// const person1 = {
//   id: 1,
//   message: 111,
// } as const;

// type PersonMessage = Message<typeof person1>;

// // 没有message返回Never;
// type Message2<T> = T extends { message: unknown } ? T["message"] : never;
// type PersonMessage2 = Message2<typeof person1>;

// 类型工具 提取具体的类型；

// type Flatten<T> = T extends any[] ? T[number] : T;
// type A = Flatten<string[]>;

// const arr = [{ id: 1, name: "qq" }];
// type A2 = Flatten<typeof arr>;

// // 条件类型嵌套
// type GetType<T> = T extends string
//   ? "string"
//   : T extends number
//   ? "number"
//   : T extends bigint
//   ? "bigint"
//   : "object";
// type T0 = GetType<12n>;

// 实现类型工具merge
type Foo = {
  name: string;
  age: string;
};
type Bar = {
  age: number;
  sex: string;
};
/**
 * Result应该变成 ：
 * {
 * name: string;
 * age: number;
 * sex: string;
 * }
 */
type Result = Merge<Foo, Bar>;

type Merge<T, U> = {};

// 联合类型会自动的去重
type A = 1 | 2 | 2 | 3 | 3;
// type Merge<T, U> = {
//   [key in keyof T | keyof U]: key extends keyof U
//     ? U[key]
//     : key extends keyof T
//     ? T[key]
//     : never;
// };
export {};
